package utils

import (
	"strconv"

	"github.com/gin-gonic/gin"
)

// ParamParser 参数解析器
type ParamParser struct {
	ctx *gin.Context
}

// NewParamParser 创建参数解析器
func NewParamParser(ctx *gin.Context) *ParamParser {
	return &ParamParser{ctx: ctx}
}

// NewParamParserDebug 调试友好的参数解析器创建函数
func NewParamParserDebug(ctx *gin.Context) *ParamParser {
	parser := &ParamParser{ctx: ctx}
	// 添加调试标记，防止编译器优化
	_ = parser.ctx
	return parser
}

// Int 获取查询参数并转换为int
func (p *ParamParser) Int(key string) int {
	value := p.ctx.DefaultQuery(key, "1")
	intValue, err := strconv.Atoi(value)
	if err != nil {
		panic("参数格式错误: " + key)
	}
	return intValue
}

// Uint 获取查询参数并转换为uint
func (p *ParamParser) Uint(key string) uint {
	value := p.ctx.DefaultQuery(key, "0")
	uintValue, err := strconv.ParseUint(value, 10, 32)
	if err != nil {
		panic("参数格式错误: " + key)
	}
	return uint(uintValue)
}

// String 获取查询参数字符串
func (p *ParamParser) String(key string) string {
	return p.ctx.DefaultQuery(key, "")
}

// Bool 获取查询参数并转换为bool
func (p *ParamParser) Bool(key string) bool {
	value := p.ctx.DefaultQuery(key, "false")
	boolValue, err := strconv.ParseBool(value)
	if err != nil {
		panic("参数格式错误: " + key)
	}
	return boolValue
}

// PathInt 获取路径参数并转换为int
func (p *ParamParser) PathInt(key string) int {
	value := p.ctx.Param(key)
	intValue, err := strconv.Atoi(value)
	if err != nil {
		panic("路径参数格式错误: " + key)
	}
	return intValue
}

// PathUint 获取路径参数并转换为uint
func (p *ParamParser) PathUint(key string) uint {
	value := p.ctx.Param(key)
	uintValue, err := strconv.ParseUint(value, 10, 32)
	if err != nil {
		panic("路径参数格式错误: " + key)
	}
	return uint(uintValue)
}

// Bind 绑定JSON请求体
func (p *ParamParser) Bind(obj interface{}) {
	if err := p.ctx.ShouldBindJSON(obj); err != nil {
		panic("请求参数格式错误")
	}
}

// BindQuery 绑定查询参数
func (p *ParamParser) BindQuery(obj interface{}) {
	if err := p.ctx.ShouldBindQuery(obj); err != nil {
		panic("查询参数格式错误")
	}
}

// UserID 从上下文中获取用户ID
func (p *ParamParser) UserID() uint {
	userID, exists := p.ctx.Get("userId")
	if !exists {
		panic("用户未登录")
	}

	if id, ok := userID.(uint); ok {
		return id
	}

	if id, ok := userID.(float64); ok {
		return uint(id)
	}

	panic("用户ID格式错误")
}

// BaseQuery 基础查询参数（所有分页查询都包含的基础参数）
type BaseQuery struct {
	Page     int
	PageSize int
	Keyword  string
	Status   int
	TenantID uint
}

// PageQuery 泛型分页查询参数结构
type PageQuery[T any] struct {
	BaseQuery
	Conditions T
}

// Page 获取基础分页参数
func (p *ParamParser) Base() BaseQuery {
	page := p.Int("page")
	pageSize := p.Int("pageSize")
	keyword := p.String("keyword")
	status := p.Int("status")
	tenantID := p.Uint("tenantId")

	// 参数验证
	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	return BaseQuery{
		Page:     page,
		PageSize: pageSize,
		Keyword:  keyword,
		Status:   status,
		TenantID: tenantID,
	}
}

// Page 获取分页查询参数（兼容旧版本）
func (p *ParamParser) Page() PageQuery[map[string]interface{}] {
	base := p.Base()
	return PageQuery[map[string]interface{}]{
		BaseQuery:  base,
		Conditions: make(map[string]interface{}),
	}
}

// PageWith 泛型方法：获取带有自定义条件的分页查询参数
func PageWith[T any](p *ParamParser) PageQuery[T] {
	base := p.Base()
	var conditions T
	return PageQuery[T]{
		BaseQuery:  base,
		Conditions: conditions,
	}
}

// PageWithQuery 泛型方法：手动绑定查询条件
func PageWithQuery[T any](p *ParamParser, conditions T) PageQuery[T] {
	base := p.Base()
	return PageQuery[T]{
		BaseQuery:  base,
		Conditions: conditions,
	}
}

// PageAutoBind 自动绑定查询条件到指定的结构体
func PageAutoBind[T any](p *ParamParser) PageQuery[T] {
	base := p.Base()
	var conditions T

	// 使用gin的绑定功能自动绑定查询参数到结构体
	if err := p.ctx.ShouldBindQuery(&conditions); err != nil {
		// 绑定失败时返回空结构体，不影响基础分页参数
		return PageQuery[T]{
			BaseQuery:  base,
			Conditions: conditions,
		}
	}

	return PageQuery[T]{
		BaseQuery:  base,
		Conditions: conditions,
	}
}

// PageResult 分页返回结果结构
type PageResult struct {
	List  interface{} `json:"list"`
	Total int64       `json:"total"`
	Page  int         `json:"page"`
	Size  int         `json:"size"`
}

// SuccessPage 分页成功响应
func SuccessPage(ctx *gin.Context, list interface{}, total int64, page, size int) {
	Success(ctx, PageResult{
		List:  list,
		Total: total,
		Page:  page,
		Size:  size,
	})
}
